package com.tao.ormlib;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;
import android.util.Log;

import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.DatabaseTable;
import com.j256.ormlite.table.TableUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class DatabaseUtil {
    public static final String TAG = "DatabaseUtil.java";

    /**
     * 数据库表操作类型
     */
    public enum OPERATION_TYPE {
        /**
         * 表保留原数据
         */
        RETAIN,
        /**
         * 表字段自动处理
         */
        AUTO
    }

    /**
     * 升级表，增加字段
     *
     * @param db
     * @param clazz *
     *              * 1.增量更新
     *              * 2.减少字段更新
     *              * 3.有增有减更新
     *              *
     *              * 1.更新保留原来字段数据
     *              * 2.更新去除多余原字段数据
     */

    public static <T> void upgradeTable(SQLiteDatabase db, ConnectionSource cs, Class<T> clazz) {
        String tableName = extractTableName(clazz);
        db.beginTransaction();
        try {
            //Rename table
            String tempTableName = tableName + "_temp";
            String sql = "ALTER TABLE " + tableName + " RENAME TO " + tempTableName;
            Log.d(TAG, "" + sql);
            db.execSQL(sql);

            //Create table
            try {
                sql = TableUtils.getCreateTableStatements(cs, clazz).get(0);
                Log.d(TAG, "" + sql);
                db.execSQL(sql);
            } catch (Exception e) {
                e.printStackTrace();
                TableUtils.createTable(cs, clazz);
            }

            //Load data
            String columns;
//            if (type == OPERATION_TYPE.ADD) {
//                columns = Arrays.toString(matchAddColumnS(db, tableName, tempTableName)).replace("[", "").replace("]", "");
//            } else if (type == OPERATION_TYPE.AUTO) {
//                columns = Arrays.toString(matchAutoColumnS(db, tableName, tempTableName)).replace("[", "").replace("]", "");
////                columns = Arrays.toString(getColumnNames(db, tableName)).replace("[", "").replace("]", "");
//            } else {
//                throw new IllegalArgumentException("OPERATION_TYPE error");
//            }

            columns = Arrays.toString(matchAutoColumnS(db, tableName, tempTableName)).replace("[", "").replace("]", "");


            sql = "INSERT INTO " + tableName +
                    " (" + columns + ") " +
                    " SELECT " + columns + " FROM " + tempTableName;
            Log.e(TAG, "" + sql);

            db.execSQL(sql);

            //Drop temp table
            sql = "DROP TABLE IF EXISTS " + tempTableName;
            Log.d(TAG, "" + sql);

            db.execSQL(sql);

            db.setTransactionSuccessful();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            db.endTransaction();
        }
    }

    /**
     * 去新表与旧表交集
     *
     * @param db
     * @param tableName
     * @param tempTableName
     * @return
     */
    private static String[] matchAutoColumnS(SQLiteDatabase db, String tableName, String tempTableName) {
        String[] oldColumnNames = getColumnNames(db, tempTableName);
        String[] newColumnNames = getColumnNames(db, tableName);
        List<String> columns = new ArrayList<>();
        for (int i = 0; i < newColumnNames.length; i++) {
            String newColumnName = newColumnNames[i];
            boolean old = false;
            for (int j = 0; j < oldColumnNames.length; j++) {
                String oldColumnName = oldColumnNames[j];
                if (newColumnName.equals(oldColumnName)) {
                    old = true;
                    break;
                }
            }
            if (old) {
                columns.add(newColumnName);
            }
        }

        return columns.toArray(new String[columns.size()]);
    }

    private static String[] matchAddColumnS(SQLiteDatabase db, String tableName, String tempTableName) {
        String[] oldColumnNames = getColumnNames(db, tempTableName);
        String[] newColumnNames = getColumnNames(db, tableName);
        List<String> newClouns = new ArrayList<>();
        for (int i = 0; i < oldColumnNames.length; i++) {
            // 原字段
            String oldColumnName = oldColumnNames[i];
            boolean match = false;
            for (int j = 0; j < newColumnNames.length; j++) {
                String newColumnName = newColumnNames[j];
                if (oldColumnName.equals(newColumnName)) {
                    match = true;
                    break;
                }
            }
            if (!match) {
                newClouns.add(oldColumnName);
            }
        }
        List<String> columes = Arrays.asList(newColumnNames);
        columes.addAll(newClouns);
        return (String[]) columes.toArray();
    }


    /**
     * 获取表名(ormlite DatabaseTableConfig.java)
     *
     * @param clazz
     * @param <T>
     * @return
     */
    private static <T> String extractTableName(Class<T> clazz) {
        DatabaseTable databaseTable = clazz.getAnnotation(DatabaseTable.class);
        String name = null;
        if (databaseTable != null && databaseTable.tableName() != null && databaseTable.tableName().length() > 0) {
            name = databaseTable.tableName();
        } else {
            /*
             * NOTE: to remove javax.persistence usage, comment the following line out
             */
//            name = JavaxPersistence.getEntityName(clazz);
            if (name == null) {
                // if the name isn't specified, it is the class name lowercased
                name = clazz.getSimpleName().toLowerCase();
            }
        }
        return name;
    }

    /**
     * 获取表的列名
     *
     * @param db
     * @param tableName
     * @return
     */
    private static String[] getColumnNames(SQLiteDatabase db, String tableName) {
        String[] columnNames = null;
        Cursor cursor = null;
        try {
            cursor = db.rawQuery("PRAGMA table_info(" + tableName + ")", null);
            if (cursor != null) {
                int columnIndex = cursor.getColumnIndex("name");
                if (columnIndex == -1) {
                    return null;
                }

                int index = 0;
                columnNames = new String[cursor.getCount()];
                for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
                    columnNames[index] = cursor.getString(columnIndex);
                    index++;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        return columnNames;
    }

    public static synchronized <T> boolean tableIsExist(SQLiteDatabase db, Class<T> clazz) {
        boolean result = false;

        String s = extractTableName(clazz);
        if (TextUtils.isEmpty(s))
            return false;
        Cursor cursor = null;
        try {
            String sql = "select count(*) as c from sqlite_master where type ='table' and name ='" + s + "' ";
            cursor = db.rawQuery(sql, null);
            if (cursor.moveToNext()) {
                int count = cursor.getInt(0);
                if (count > 0) {
                    result = true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return result;
    }
}